#include "wifi_adapter.h"
#include "iot_uart.h"
#include "queue.h"
#include "stdio.h"
#include "string.h"
#include "stdint.h"

/**
 * @brief Enables the hotspot mode.
 *
 * Before using this function, you need to invoke {@link SetHotspotConfig} and set at least the SSID, security type,
 * and key. \n
 *
 * @return Returns {@link WIFI_SUCCESS} if the hotspot mode is enabled; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
extern NetModeType g_mode;
uint8_t g_stationQueue = 0xff;
extern QueueInfo g_queueInfo[QUEUE_MAX];
extern uint8_t g_wifiEventQueue;
StationInfo station_old[WIFI_MAX_STA_NUM]={0}, station_new[WIFI_MAX_STA_NUM]={0};

void HotspotChangeCB(WifiErrorCode res)
{   
    if(g_wifiEventQueue != 0xff){
        QUEUE_NODE *tmp;
        LOS_DL_LIST_FOR_EACH_ENTRY(tmp, &g_queueInfo[g_wifiEventQueue].head, QUEUE_NODE, s_list){
            if(((WifiEvent *)(tmp->user_data))->OnHotspotStateChanged == NULL)
                continue;
            if(res == WIFI_SUCCESS){
                ((WifiEvent *)(tmp->user_data))->OnHotspotStateChanged(WIFI_STATE_AVAILABLE);
            }
            else{
                ((WifiEvent *)(tmp->user_data))->OnHotspotStateChanged(WIFI_STATE_NOT_AVAILABLE);
            }
        }
    }
}
void HotspotStaJoinCB(StationInfo *info)
{
    if(g_wifiEventQueue != 0xff){
        QUEUE_NODE *tmp;
        LOS_DL_LIST_FOR_EACH_ENTRY(tmp, &g_queueInfo[g_wifiEventQueue].head, QUEUE_NODE, s_list){
            if(((WifiEvent *)(tmp->user_data))->OnHotspotStaJoin == NULL)
                continue;
            ((WifiEvent *)(tmp->user_data))->OnHotspotStaJoin(info);
        }
    }
}

void HotspotStaLeaveCB(StationInfo *info)
{
    if(g_wifiEventQueue != 0xff){
        QUEUE_NODE *tmp;
        LOS_DL_LIST_FOR_EACH_ENTRY(tmp, &g_queueInfo[g_wifiEventQueue].head, QUEUE_NODE, s_list){
            if(((WifiEvent *)(tmp->user_data))->OnHotspotStaLeave == NULL)
                continue;
            ((WifiEvent *)(tmp->user_data))->OnHotspotStaLeave(info);
        }
    }
}

WifiErrorCode EnableHotspot(void)
{
    WifiErrorCode res=WIFI_SUCCESS;
#if WIFI_DEBUG
    printf("Enable Hotspot ... ");
    fflush(stdout);
#endif
    // 设置模式3，同时具备终端和热点的功能
    char mode = ATA_AP;
    res = SendWifiCommand(WIFI_SET_MODE, &mode);
    if (res == WIFI_SUCCESS)
    {
        res = WaitWifiResponse(WIFI_SET_MODE, (char *)(&g_mode), WIFI_TIMEOUT);
        if (res == WIFI_SUCCESS){
            // 如果开启热点，需要创建队列，保存加入的station
            if(g_stationQueue == 0xff){
                QueueCreate(&g_stationQueue, 36, WIFI_MAX_STA_NUM);
            }
        }
    }
    // 状态回调
    HotspotChangeCB(res);
#if WIFI_DEBUG
    PrintWifiError(res);
#endif
    return res;
}

/**
 * @brief Disables the hotspot mode.
 *
 * @return Returns {@link WIFI_SUCCESS} if the hotspot mode is disabled; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode DisableHotspot(void)
{
    WifiErrorCode res=WIFI_SUCCESS;
#if WIFI_DEBUG
    printf("Enable Hotspot ... ");
    fflush(stdout);
#endif
    // 设为终端模式，没有热点功能
    char mode = STA;
    res = SendWifiCommand(WIFI_SET_MODE, &mode);
    if (res == WIFI_SUCCESS)
    {
        res = WaitWifiResponse(WIFI_SET_MODE, (char *)(&g_mode), WIFI_TIMEOUT);
        if (res == WIFI_SUCCESS){
            // 销毁station队列
            QueueDestroy(g_stationQueue);
        }
    }
    // 状态回调
    HotspotChangeCB(res);
#if WIFI_DEBUG
    PrintWifiError(res);
#endif
    return res;
}

/**
 * @brief Sets a specified hotspot configuration.
 *
 * The hotspot configuration includes the SSID, security type, and key. The configuration set overwrites the existing
 * configuration and takes effect after the hotspot mode is re-enabled. \n
 * Before enabling the hotspot mode for the first time, you must call this function. \n
 *
 * @param config Indicates the hotspot configuration to set.
 * @return Returns {@link WIFI_SUCCESS} if the hotspot configuration is set; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode SetHotspotConfig(const HotspotConfig *config)
{
    WifiErrorCode res=WIFI_SUCCESS;
#if WIFI_DEBUG
    printf("Set Hotspot config ... ");
    fflush(stdout);
#endif
    // 参数检测
    if(config == NULL){
        return ERROR_WIFI_INVALID_ARGS;
    }
    // 发送指令，需要将config作为参数传入
    res = SendWifiCommand(AP_SET_PARAM, (char *)config);
    if (res == WIFI_SUCCESS){
        // 等待应答
        res = WaitWifiResponse(AP_SET_PARAM, NULL, WIFI_TIMEOUT);
    }
#if WIFI_DEBUG
    PrintWifiError(res);
#endif
    return res;
}

/**
 * @brief Obtains a specified hotspot configuration.
 *
 * The hotspot configuration includes the SSID, security type, and key. \n
 *
 * @param result Indicates the obtained hotspot configuration.
 * @return Returns {@link WIFI_SUCCESS} if the hotspot configuration is obtained; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode GetHotspotConfig(HotspotConfig *result)
{
    WifiErrorCode res=WIFI_SUCCESS;
#if WIFI_DEBUG
    printf("Get Hotspot config... ");
    fflush(stdout);
#endif
    // 参数检测
    if(result == NULL){
        return ERROR_WIFI_INVALID_ARGS;
    }
    // 发送指令
    res = SendWifiCommand(AP_GET_PARAM, NULL);
    if (res == WIFI_SUCCESS){
        // result存放应答结果
        res = WaitWifiResponse(AP_GET_PARAM, (char *)result, WIFI_TIMEOUT);
    }
#if WIFI_DEBUG
    PrintWifiError(res);
#endif
    return res;
}

/**
 * @brief Checks whether the hotspot mode is enabled.
 *
 * @return Returns {@link WIFI_HOTSPOT_ACTIVE} if the hotspot mode is enabled; returns {@link WIFI_HOTSPOT_NOT_ACTIVE}
 * otherwise.
 * @since 7
 */
int IsHotspotActive(void)
{
    WifiErrorCode res;
    // 获取模式
    res = SendWifiCommand(WIFI_GET_MODE, NULL);
    if (res == WIFI_SUCCESS)
    {
        // 等待应答，模式值回传到参数g_mode
        res = WaitWifiResponse(WIFI_GET_MODE, (char *)(&g_mode), WIFI_TIMEOUT);
        if (res == WIFI_SUCCESS)
        {
            // 判断热点功能是否打开
            if (g_mode == ATA_AP)
                return WIFI_HOTSPOT_ACTIVE;
        }
    }
    return WIFI_HOTSPOT_NOT_ACTIVE;
}

/**
 * @brief Obtains an array of stations connected to this hotspot.
 *
 * The station information is defined in {@link StationInfo}. \n
 *
 * @param result Indicates the array of stations connected to this hotspot. The array is requested and released by the
 * caller. The value must be greater than or equal to {@link WIFI_MAX_STA_NUM}.
 * @param size Indicates the size of the array.
 * @return Returns {@link WIFI_SUCCESS} if the array of stations connected to this hotspot is obtained; returns an error
 *  code defined in {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode GetStationList(StationInfo *result, unsigned int *size)
{
    WifiErrorCode res=WIFI_SUCCESS;
#if WIFI_DEBUG
    printf("Enable Hotspot ... ");
    fflush(stdout);
#endif
    if(result==NULL || size==NULL)
        return ERROR_WIFI_INVALID_ARGS;
    res = SendWifiCommand(AP_LIST_CLIENT, NULL);
    if (res == WIFI_SUCCESS){
        // 等待应答，模式值回传到参数result
        res = WaitWifiResponse(AP_LIST_CLIENT, (char *)result, WIFI_TIMEOUT);
        if (res == WIFI_SUCCESS){
            // 解析数据
            char buf[36] = {0};
            *size = g_queueInfo[g_stationQueue].cur_len;
            uint8_t i=0;
            for(i=0; i<(*size); i++){
                memset(buf, 0, 36);
                QueueOut(g_stationQueue, buf);
                char *tmp, *saveptr;
                tmp = strtok_r(buf, ",", &saveptr);
                result[i].ipAddress = ip_to_int(tmp);
                mac_str2hex((char *)(result[i].macAddress), saveptr);
                result[i].name = NULL;
                result[i].disconnectedReason = 0;
            } 
        }
    }
#if WIFI_DEBUG
    PrintWifiError(res);
#endif
    return res;
}
/**
 * @brief Disconnects from the station with a specified MAC address.
 *
 * @param mac Indicates the pointer to the MAC address of the station.
 * @param macLen Indicates the length of the MAC address of the station.
 * @return Returns {@link WIFI_SUCCESS} if the function is successfully called;
 * returns an error code defined in {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode DisassociateSta(unsigned char *mac, int macLen)
{
    WifiErrorCode res=ERROR_WIFI_NOT_SUPPORTED;
#if WIFI_DEBUG
    printf("Disconnects from the station ... ");
    fflush(stdout);
#endif

#if WIFI_DEBUG
    PrintWifiError(res);
#endif
    return res;
}

/**
 * @brief Adds the hotspot transmit power to the beacon.
 *
 * After the transmit power is added, the beacon must contain specified IEs. If the minimum transmit power
 * <b>0xFFFFFFFF</b> is added, the beacon does not contain the IEs. \n
 * The transmit power is added to the <b>ie</b> field only, exerting no impacts on the transmit power. \n
 * @param power Indicates the transmit power to add.
 * @return Returns {@link WIFI_SUCCESS} if the function is successfully called; returns an error code defined
 * in {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode AddTxPowerInfo(int power)
{
    WifiErrorCode res=ERROR_WIFI_NOT_SUPPORTED;

    return res;
}

/**
 * @brief Sets the frequency band for this hotspot.
 *
 * @param band Indicates the frequency band to set.
 * @return Returns {@link WIFI_SUCCESS} if the frequency band is set; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode SetBand(int band)
{
    WifiErrorCode res=WIFI_SUCCESS;
    if(HOTSPOT_BAND_TYPE_2G == band)
        res = WIFI_SUCCESS;
    else
        res = ERROR_WIFI_NOT_SUPPORTED;
    return res;
}

/**
 * @brief Obtains the frequency band of this hotspot.
 *
 * @param result Indicates the obtained frequency band.
 * @return Returns {@link WIFI_SUCCESS} if the frequency band is obtained; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode GetBand(int *result)
{
    WifiErrorCode res=WIFI_SUCCESS;
    *result = HOTSPOT_BAND_TYPE_2G;
    return res;
}

void StationListener()
{
    // connect  disconnect 121213123123123 disconnect
    unsigned int size, station_flag=0;
    char mac[6] = {0};
    // 读取已经加入的station列表
    GetStationList(station_new, &size);
    // 从旧列表查找是否包含新列表的数据，如果不包含，则代表有新设备加入
    for(int i=0; i<WIFI_MAX_STA_NUM; i++){
        station_flag = 0;
        for(int j=0; j<WIFI_MAX_STA_NUM; j++){
            if(memcmp(station_new[i].macAddress, station_old[j].macAddress, 6) == 0){
                station_flag = 1;
                break;
            }
        }
        // 在old内部没找到new的成员
        if(memcmp(station_new[i].macAddress, mac, 6)==0 && station_flag==0)
            HotspotStaJoinCB(&station_new[i]);
    }
    // 从新列表查找是否包含旧列表的数据，如果不包含，则代表有设备离开
    for(int i=0; i<WIFI_MAX_STA_NUM; i++){
        station_flag = 0;
        for(int j=0; j<WIFI_MAX_STA_NUM; j++){
            if(memcmp(station_old[i].macAddress, station_new[j].macAddress, 6) == 0){
                station_flag = 1;
                break;
            }
        }
        // 在old内部没找到new的成员
        if(memcmp(station_old[i].macAddress, mac, 6)==0 && station_flag==0)
            HotspotStaLeaveCB(&station_old[i]);
    }
    // 覆盖旧数据
    memcpy(station_old, station_new, WIFI_MAX_STA_NUM*sizeof(StationInfo));
}